package com.atguigu.search.thread;

import java.util.concurrent.*;

/**
 * description: ThreadTest
 * date: 2022/11/28 21:04
 * author: MR.孙
 */
public class ThreadTest {
    public static ExecutorService executorSrevice = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("thread main start...");

   /*     CompletableFuture.runAsync(()->{
                    System.out.println("当前线程:->" + Thread.currentThread().getId());
                    int i = 10/5;
                    System.out.println("运行结果:" + i);
                }
                ,executorSrevice);*/

        /**
         * 方法完成后的感知
         */
        /*CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:->" + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("运行结果:" + i);
            return i;
        }, executorSrevice).whenComplete((result,exception)->{
            System.out.println("异步任务完成了...结果是:" + result + "异常是:" + exception);
        }).exceptionally(throwable -> {
            return 10;
        });*/

        /**
         * 方法完成后的处理
         */
    /*    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:->" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, executorSrevice).handle((result,exception)->{
            if (result!=null) {
                return result*2;
            }

            if (exception!=null) {
                return 0;
            }
            return 0;
        });

        Integer i = future.get();*/

        /**
         * 线程串行化
         * 1. thenRunAsync 不能获取上一步的执行结果
         * 2. thenAcceptAsync 能接受上一步结果，但是无返回值
         * 3. 能接受上一步结果，有返回值
         */

       /* CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:->" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, executorSrevice).thenRunAsync(() -> {
            System.out.println("任务2启动了...");
        }, executorSrevice);*/

      /*  CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:->" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, executorSrevice).thenAcceptAsync(result -> {
            //void accept(T t); 能接受上一步结果，但是无返回值
            System.out.println("任务2启动了..." + result);
        }, executorSrevice);*/

      /*  CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:->" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, executorSrevice).thenApplyAsync((result) -> {
            System.out.println("任务2启动了..." + result);
            return "Hello" + result;
        }, executorSrevice);

        String s = future.get();*/

        /**
         * 两任务组合 - 都要完成
         * thenCombine：组合两个 future，获取两个 future 的返回结果，并返回当前任务的返回值
         * thenAcceptBoth：组合两个 future，获取两个 future 任务的返回结果，然后处理任务，没有
         * 返回值。
         * runAfterBoth：组合两个 future，不需要获取 future 的结果，只需两个 future 处理完任务后，
         * 处理该任务。
         */

       /* CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程开始:->" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1结束");
            return i;
        }, executorSrevice);


        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程开始:->" + Thread.currentThread().getId());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("任务2结束");
            return "Hello";
        }, executorSrevice);*/

       /* future01.runAfterBothAsync(future02, ()->{
            System.out.println("任务3开始...");
        }, executorSrevice);*/

     /*   future01.thenAcceptBothAsync(future02, (f1, f2)->{
            System.out.println("任务3开始...之前的结果：" + f1 + "->" + f2);
        }, executorSrevice);*/

        /*CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
            return f1 + ":" + f2 + "->Haha";
        }, executorSrevice);*/


        /**
         * 两个任务, 只要有一个完成， 我们就执行任务3
         * runAfterEitherAsync: 不感知结果，自己没有返回值
         * acceptEitherAsync: 感知结果，自己没有返回值
         * applyToEitherAsync:  感知结果，自己有返回值
         */

   /*     future01.runAfterEitherAsync(future02, ()->{
            System.out.println("任务3开始...");
        }, executorSrevice);*/

      /*  future01.acceptEitherAsync(future02, (result)->{
            System.out.println("任务3开始...上一步的结果->" + result);
        }, executorSrevice);*/

       /* CompletableFuture<String> future = future01.applyToEitherAsync(future02, res -> {
            return res.toString() + "->哈哈";
        }, executorSrevice);*/


        /**
         * 多个组合
         *      全部执行完
         *      一个执行完
         */
        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.jpg";
        }, executorSrevice);

        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的属性");
            return "黑色+256G";
        }, executorSrevice);

        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
                System.out.println("查询商品介绍");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "华为";
        }, executorSrevice);

        //获取返回结果，会进行阻塞，但是又因为是异步的，所以花费时间还是某个花费时间最长的任务，阻塞只是控制顺序

        //下面的代码会冗余， 所以我们要用到allOf或者anyOf ,
      /*  futureImg.get();
        futureAttr.get();
        futureDesc.get();*/

        // CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);

        //获取所有结果返回
        System.out.println("thread main end..." + anyOf.get());
    }


    public static void thread(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("thread main start...");
        /**
         * 1. 继承Thread,重写run方法
         *      System.out.println("thread main start...");
         *         new Thread01().start();
         *      System.out.println("thread main end...");
         *
         *2. 实现Runnable接口，重写run方法
         *         System.out.println("thread main start...");
         *         new Thread(new Runnable01()).start();
         *         System.out.println("thread main end...");
         * 3. Callable接口 + FutureTask(可以拿到返回结果，可以处理异常)
         *         //阻塞等待整个线程执行完成， 获取返回结果
         *         FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
         *         new Thread(futureTask).start();
         *         Integer i = futureTask.get();
         *         System.out.println("获取Callable的值->" + i);
         * 4.线程池
         *    给线程池直接提交任务
         *    service.execute(new Runnable01());
         *
         *
         * 区别:
         *     1、2不能得到返回值，3可以获取返回值
         *     1、2、3都不能控制资源
         *     4可以控制资源，性能稳定
         */

        //我们以后在业务代码里面，以上三种启动线程的方式都不用。【将所有的多线程异步任务都交给线程池执行】
        //当前系统中池只有一两个(业务和非业务), 每个异步任务， 提交给线程池让它自己去执行就行

        new ThreadPoolExecutor(5,
                200,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()

        );


        System.out.println("thread main end...");

    }

    public static class Thread01 extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println("线程名:->" + Thread.currentThread().getName() +
                        "线程号:->" +  Thread.currentThread().getId());
            }
        }
    }

    public static class Runnable01 implements Runnable{

        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println("线程名:->" + Thread.currentThread().getName() +
                        "线程号:->" +  Thread.currentThread().getId());
            }
        }
    }

    public static class Callable01 implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程:->" + Thread.currentThread().getId());
            int i = 10/5;
            System.out.println("运行结果:" + i);
            return i;
        }
    }




}
